package hit.dao.database;

import hit.core.HITBase;
import hit.dao.DAOBase;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public abstract class DBBase implements DAOBase {
	
	protected DatabaseDAO databaseDAO;
	
	public DBBase(DatabaseDAO databaseDAO)
	{
		this.databaseDAO = databaseDAO;
	}
	
	/**
	 * Template for getting all objects of a certain type from the DAO
	 * @return a List of all HIT objects in the data source
	 * */
	public List<HITBase> GetAll() {
		PreparedStatement stmt = null;
		ResultSet rs = null;
		List<HITBase> result = null;
		
		//query the database to get all the objects in the database
		try {
			try {
				//have the individual daos initialize their prepared statement
				stmt = InitGetQuery();
			    
				//execute the query and hand the result set to the child class to process
			    rs = stmt.executeQuery();
			    result = ProcessGetRS(rs);
			    
			}
			finally {//close up resources
			    if (stmt != null) 
			    	stmt.close();
			    if (rs != null)
			    	rs.close();
			}
		}
		catch (SQLException e) {
		    e.printStackTrace();
		}
		
		return result;
	}
	
	/**
	 * Setup the prepared statement for getting all
	 * @return the completed PreparedStatement
	 * @throws SQLException 
	 * */
	protected abstract PreparedStatement InitGetQuery() throws SQLException;
	
	/**
	 * Handle the resulting get all Result Statement and turn it into a List of HIT objects
	 * @return the processed HIT Objects
	 * @throws SQLException 
	 * */
	protected abstract List<HITBase> ProcessGetRS(ResultSet rs) throws SQLException;

	/**
	 * Template for creating an object in the data source
	 * @param object the HIT object to add to the data source
	 * */
	public int Create(HITBase object) {
		List<PreparedStatement> stmts = null;
		int newId = 0;
		
		try {
			try {
				//have the individual daos initialize their create statement
				stmts = InitCreateStatement(object);
			    
				for (PreparedStatement stmt: stmts)
				{
					if (stmt.execute())
					{
						ResultSet set = stmt.getResultSet();
						newId = set.getInt(1);
					}
					else
					{
						// Update, insert or delete. Do nothing.
					}
				}
			    
			}
			finally {//close up resources
			    if (stmts != null) {
			    	for (PreparedStatement stmt: stmts) {
			    		stmt.close();
			    	}
			    }
			}
		}
		catch (SQLException e) {
		    e.printStackTrace();
		}
		
		return newId;
	}
	
	/**
	 * Prepare a list of statements that insert the object passed in into the database
	 * @param object the Object to insert
	 * @return the completed PreparedStatements
	 * @throws SQLException 
	 * */
	protected abstract List<PreparedStatement> InitCreateStatement(HITBase object) 
			throws SQLException;

	/**
	 * Template for removing an object from the data source
	 * @param object the HIT object to remove from the data source
	 * */
	public void Remove(HITBase object) {
		List<PreparedStatement> stmts = null;
		
		try {
			try {
				//have the individual daos initialize their remove statement
				stmts = InitRemoveStatement(object);
			    
				for (PreparedStatement stmt: stmts)
					stmt.executeUpdate();
			    
			}
			finally {//close up resources
			    if (stmts != null) {
			    	for (PreparedStatement stmt: stmts)
			    		stmt.close();
			    }
			    	
			}
		}
		catch (SQLException e) {
		    e.printStackTrace();
		}
	}

	/**
	 * Prepare a list of statements that remove the object passed in into the database
	 * @param object the Object to remove
	 * @return the completed PreparedStatements
	 * @throws SQLException 
	 * */
	protected abstract List<PreparedStatement> InitRemoveStatement(HITBase object)
			throws SQLException;
	
	/**
	 * Template for updating an object in the database
	 * @param object the Object to update
	 */
	public void Update(HITBase object) {
		List<PreparedStatement> stmts = null;
		
		try {
			try {
				//have the individual daos initialize their prepared statement
				stmts = InitUpdateQuery(object);
			    
				for (PreparedStatement stmt: stmts) {
					stmt.executeUpdate();
				}
			    
			}
			finally {//close up resources
			    if (stmts != null) {
			    	for (PreparedStatement stmt: stmts) {
			    		stmt.close();
			    	}
			    }
			}
		}
		catch (SQLException e) {
		    e.printStackTrace();
		}
	}

	/**
	 * Prepare a statement to update an object in the database
	 * @param object the Object to update*/
	protected abstract List<PreparedStatement> InitUpdateQuery(HITBase object) throws SQLException;
}
